package com.limh.blehelper;

import android.annotation.SuppressLint;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;

import com.limh.blehelper.event.BlueValue;
import com.limh.blehelper.event.ConnectEvent;
import com.limh.blehelper.service.BlueConnectService;
import com.limh.blehelper.service.BlueScanningService;
import com.limh.blehelper.utils.BleLog;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * Function:
 * author: limh
 * time:2018/1/19
 */

public class Ble2Manager {
    private Application context;
    public BluetoothAdapter bluetoothAdapter;
    private ConnectedThread connectedThread;
    private BluetoothDevice currentDevice;

    @SuppressLint("StaticFieldLeak")
    private static Ble2Manager ble2Manager = null;

    public static Ble2Manager getInstance() {
        if (null == ble2Manager) {
            ble2Manager = new Ble2Manager();
        }
        return ble2Manager;
    }

    public void init(Application app) {
        if (null == context && null != app) {
            context = app;
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        }
    }

    public boolean isSupportBle() {
        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
    }

    public void openBle() {
        if (null != bluetoothAdapter) {
            bluetoothAdapter.enable();
        }
    }

    public void closeBle() {
        if (null != bluetoothAdapter) {
            if (bluetoothAdapter.isEnabled()) {
                bluetoothAdapter.disable();
            }
        }
    }

    public BluetoothDevice getCurrentDevice() {
        return currentDevice;
    }

    public void setCurrentDevice(BluetoothDevice currentDevice) {
        this.currentDevice = currentDevice;
    }

    public boolean isBleEnable() {
        return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
    }

    /**
     * 获取已配对的设备列表
     *
     * @return 返回配对的蓝牙列表
     */
    public List<BluetoothDevice> getBondedDevices() {
        List<BluetoothDevice> list = new ArrayList<>();
        if (null != bluetoothAdapter) {
            Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
            if (null != pairedDevices && pairedDevices.size() > 0) {
                list.addAll(pairedDevices);
            }
        }
        return list;
    }

    public void sendByHex(byte[] hex) {
        if (null != connectedThread) {
            BleLog.d("send hex:" + (new String(hex)));
            connectedThread.write(hex);
        }
    }

    public void sendByStr(String hex) {
        if (null != connectedThread) {
            BleLog.d("send Str=" + hex);
            connectedThread.write(hex.getBytes());
        }
    }

    public void scan() {
        //注册蓝牙扫描服务
        Intent intent = new Intent(context, BlueScanningService.class);
        context.startService(intent);
    }

    public void connect(BluetoothDevice device, final String uuid) {

        if (null != connectedThread) {
            try {
                connectedThread.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //注册蓝牙连接服务
        Intent intent = new Intent(context, BlueConnectService.class);
        intent.putExtra("device",device);
        context.startService(intent);

        if (null != bluetoothAdapter && bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
        }
        EventBus.getDefault().post(new ConnectEvent(ConnectEvent.CONN_START));
        ConnectThread connectThread = new ConnectThread(device, uuid);
        connectThread.start();
    }

    private class ConnectThread extends Thread {
        private BluetoothDevice device;
        private String uuid;

        private ConnectThread(BluetoothDevice device, String uuid) {
            this.device = device;
            this.uuid = uuid;
        }

        @Override
        public void run() {
            BluetoothSocket mSocket = null;
            try {
                mSocket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString(uuid));
                mSocket.connect();
                BleLog.e("连接成功");
            } catch (final IOException e) {
                if (null != mSocket) {
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
                EventBus.getDefault().post(new ConnectEvent(ConnectEvent.CONN_FAIL, e.getMessage()));
                e.printStackTrace();
            }
            connectedThread = new ConnectedThread(mSocket);
            connectedThread.start();
        }
    }

    /**
     * 数据监控线程
     */
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mSocket;
        private InputStream mmInStream;
        private OutputStream mmOutStream;
        private boolean isClose = false;

        ConnectedThread(BluetoothSocket mSocket) {
            this.mSocket = mSocket;
            isClose = false;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = mSocket.getInputStream();
                tmpOut = mSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
                BleLog.e("ConnectedThread", "创建数据通道异常：" + e.toString());
            }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        @Override
        public void run() {
            BleLog.d("ConnectedThread", "开始接收数据");
            byte[] buffer = new byte[1024];
            while (!isClose) {
                try {
                    int count = mmInStream.read(buffer);
                    final String s = URLDecoder.decode(new String(buffer, 0, count), "UTF-8");
                    //收到数据
                    EventBus.getDefault().post(new BlueValue(s.getBytes()));
                    BleLog.w("ConnectedThread", "read=" + s);
                } catch (Exception e) {
                    e.printStackTrace();
                    BleLog.e("接收数据异常：" + e.toString());
                    if (null != mSocket) {
                        try {
                            mSocket.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                    if (null != mmInStream) {
                        try {
                            mmInStream.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                    if (null != mmOutStream) {
                        try {
                            mmOutStream.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                    break;
                }
            }
        }

        void write(byte[] bytes) {
            try {
                mmOutStream.write(bytes);
                mmOutStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        void close() throws IOException {
            isClose = true;
            if (null != mSocket) {
                mSocket.close();
            }
            if (null != mmInStream) {
                mmInStream.close();
            }
            if (null != mmOutStream) {
                mmOutStream.close();
            }
        }

    }

    public void destory() {
        Intent intent = new Intent(context, BlueScanningService.class);
        context.stopService(intent);
        if (null != bluetoothAdapter) {
            bluetoothAdapter = null;
        }
        if (null != context) {
            context = null;
        }
    }
}
